{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "Za8-Nr5k11fh"
      },
      "source": [
        "##### Copyright 2018 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "Eq10uEbw0E4l"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "nuRx7K-sirJr"
      },
      "source": [
        "# Forecasting with an RNN"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "97jsq1rHh2Ds"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/examples/blob/master/courses/udacity_intro_to_tensorflow_for_deep_learning/l08c06_forecasting_with_rnn.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://github.com/tensorflow/examples/blob/master/courses/udacity_intro_to_tensorflow_for_deep_learning/l08c06_forecasting_with_rnn.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" />View source on GitHub</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vidayERjaO5q"
      },
      "source": [
        "## Setup"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "gqWabzlJ63nL"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import tensorflow as tf\n",
        "\n",
        "keras = tf.keras"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "cg1hfKCPldZG"
      },
      "outputs": [],
      "source": [
        "def plot_series(time, series, format=\"-\", start=0, end=None, label=None):\n",
        "    plt.plot(time[start:end], series[start:end], format, label=label)\n",
        "    plt.xlabel(\"Time\")\n",
        "    plt.ylabel(\"Value\")\n",
        "    if label:\n",
        "        plt.legend(fontsize=14)\n",
        "    plt.grid(True)\n",
        "    \n",
        "def trend(time, slope=0):\n",
        "    return slope * time\n",
        "  \n",
        "  \n",
        "def seasonal_pattern(season_time):\n",
        "    \"\"\"Just an arbitrary pattern, you can change it if you wish\"\"\"\n",
        "    return np.where(season_time < 0.4,\n",
        "                    np.cos(season_time * 2 * np.pi),\n",
        "                    1 / np.exp(3 * season_time))\n",
        "\n",
        "  \n",
        "def seasonality(time, period, amplitude=1, phase=0):\n",
        "    \"\"\"Repeats the same pattern at each period\"\"\"\n",
        "    season_time = ((time + phase) % period) / period\n",
        "    return amplitude * seasonal_pattern(season_time)\n",
        "  \n",
        "  \n",
        "def white_noise(time, noise_level=1, seed=None):\n",
        "    rnd = np.random.RandomState(seed)\n",
        "    return rnd.randn(len(time)) * noise_level\n",
        "  \n",
        "  \n",
        "def window_dataset(series, window_size, batch_size=32,\n",
        "                   shuffle_buffer=1000):\n",
        "    dataset = tf.data.Dataset.from_tensor_slices(series)\n",
        "    dataset = dataset.window(window_size + 1, shift=1, drop_remainder=True)\n",
        "    dataset = dataset.flat_map(lambda window: window.batch(window_size + 1))\n",
        "    dataset = dataset.shuffle(shuffle_buffer)\n",
        "    dataset = dataset.map(lambda window: (window[:-1], window[-1]))\n",
        "    dataset = dataset.batch(batch_size).prefetch(1)\n",
        "    return dataset\n",
        "  \n",
        "def model_forecast(model, series, window_size):\n",
        "    ds = tf.data.Dataset.from_tensor_slices(series)\n",
        "    ds = ds.window(window_size, shift=1, drop_remainder=True)\n",
        "    ds = ds.flat_map(lambda w: w.batch(window_size))\n",
        "    ds = ds.batch(32).prefetch(1)\n",
        "    forecast = model.predict(ds)\n",
        "    return forecast"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "iL2DDjV3lel6"
      },
      "outputs": [],
      "source": [
        "time = np.arange(4 * 365 + 1)\n",
        "\n",
        "slope = 0.05\n",
        "baseline = 10\n",
        "amplitude = 40\n",
        "series = baseline + trend(time, slope) + seasonality(time, period=365, amplitude=amplitude)\n",
        "\n",
        "noise_level = 5\n",
        "noise = white_noise(time, noise_level, seed=42)\n",
        "\n",
        "series += noise\n",
        "\n",
        "plt.figure(figsize=(10, 6))\n",
        "plot_series(time, series)\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "Zmp1JXKxk9Vb"
      },
      "outputs": [],
      "source": [
        "split_time = 1000\n",
        "time_train = time[:split_time]\n",
        "x_train = series[:split_time]\n",
        "time_valid = time[split_time:]\n",
        "x_valid = series[split_time:]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "vDs_w3kZ8OIw"
      },
      "source": [
        "## Simple RNN Forecasting"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YU4xRp9G8OIx"
      },
      "outputs": [],
      "source": [
        "keras.backend.clear_session()\n",
        "tf.random.set_seed(42)\n",
        "np.random.seed(42)\n",
        "\n",
        "window_size = 30\n",
        "train_set = window_dataset(x_train, window_size, batch_size=128)\n",
        "\n",
        "model = keras.models.Sequential([\n",
        "  keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1),\n",
        "                      input_shape=[None]),\n",
        "  keras.layers.SimpleRNN(100, return_sequences=True),\n",
        "  keras.layers.SimpleRNN(100),\n",
        "  keras.layers.Dense(1),\n",
        "  keras.layers.Lambda(lambda x: x * 200.0)\n",
        "])\n",
        "lr_schedule = keras.callbacks.LearningRateScheduler(\n",
        "    lambda epoch: 1e-7 * 10**(epoch / 20))\n",
        "optimizer = keras.optimizers.SGD(lr=1e-7, momentum=0.9)\n",
        "model.compile(loss=keras.losses.Huber(),\n",
        "              optimizer=optimizer,\n",
        "              metrics=[\"mae\"])\n",
        "history = model.fit(train_set, epochs=100, callbacks=[lr_schedule])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YJTlFAXF8OIy"
      },
      "outputs": [],
      "source": [
        "plt.semilogx(history.history[\"lr\"], history.history[\"loss\"])\n",
        "plt.axis([1e-7, 1e-4, 0, 30])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "T3yNjxWE8OIz"
      },
      "outputs": [],
      "source": [
        "keras.backend.clear_session()\n",
        "tf.random.set_seed(42)\n",
        "np.random.seed(42)\n",
        "\n",
        "window_size = 30\n",
        "train_set = window_dataset(x_train, window_size, batch_size=128)\n",
        "valid_set = window_dataset(x_valid, window_size, batch_size=128)\n",
        "\n",
        "model = keras.models.Sequential([\n",
        "  keras.layers.Lambda(lambda x: tf.expand_dims(x, axis=-1),\n",
        "                      input_shape=[None]),\n",
        "  keras.layers.SimpleRNN(100, return_sequences=True),\n",
        "  keras.layers.SimpleRNN(100),\n",
        "  keras.layers.Dense(1),\n",
        "  keras.layers.Lambda(lambda x: x * 200.0)\n",
        "])\n",
        "optimizer = keras.optimizers.SGD(lr=1.5e-6, momentum=0.9)\n",
        "model.compile(loss=keras.losses.Huber(),\n",
        "              optimizer=optimizer,\n",
        "              metrics=[\"mae\"])\n",
        "early_stopping = keras.callbacks.EarlyStopping(patience=50)\n",
        "model_checkpoint = keras.callbacks.ModelCheckpoint(\n",
        "    \"my_checkpoint\", save_best_only=True)\n",
        "model.fit(train_set, epochs=500,\n",
        "          validation_data=valid_set,\n",
        "          callbacks=[early_stopping, model_checkpoint])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4KuPtKFe8OI0"
      },
      "outputs": [],
      "source": [
        "model = keras.models.load_model(\"my_checkpoint\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "cxq09qOg8OI1"
      },
      "outputs": [],
      "source": [
        "rnn_forecast = model_forecast(\n",
        "    model,\n",
        "    series[split_time - window_size:-1],\n",
        "    window_size)[:, 0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "PkC_JssS8OI2"
      },
      "outputs": [],
      "source": [
        "plt.figure(figsize=(10, 6))\n",
        "plot_series(time_valid, x_valid)\n",
        "plot_series(time_valid, rnn_forecast)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "1mwfgEK08OI3"
      },
      "outputs": [],
      "source": [
        "keras.metrics.mean_absolute_error(x_valid, rnn_forecast).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "KNG7s8jt8OI4"
      },
      "source": [
        "## Sequence-to-Sequence Forecasting"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "bsKGxfiE8OI4"
      },
      "outputs": [],
      "source": [
        "def seq2seq_window_dataset(series, window_size, batch_size=32,\n",
        "                           shuffle_buffer=1000):\n",
        "    series = tf.expand_dims(series, axis=-1)\n",
        "    ds = tf.data.Dataset.from_tensor_slices(series)\n",
        "    ds = ds.window(window_size + 1, shift=1, drop_remainder=True)\n",
        "    ds = ds.flat_map(lambda w: w.batch(window_size + 1))\n",
        "    ds = ds.shuffle(shuffle_buffer)\n",
        "    ds = ds.map(lambda w: (w[:-1], w[1:]))\n",
        "    return ds.batch(batch_size).prefetch(1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "5Nk2C7WP8OI5"
      },
      "outputs": [],
      "source": [
        "for X_batch, Y_batch in seq2seq_window_dataset(tf.range(10), 3,\n",
        "                                               batch_size=1):\n",
        "    print(\"X:\", X_batch.numpy())\n",
        "    print(\"Y:\", Y_batch.numpy())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4JSc-Btk8OI7"
      },
      "outputs": [],
      "source": [
        "keras.backend.clear_session()\n",
        "tf.random.set_seed(42)\n",
        "np.random.seed(42)\n",
        "\n",
        "window_size = 30\n",
        "train_set = seq2seq_window_dataset(x_train, window_size,\n",
        "                                   batch_size=128)\n",
        "\n",
        "model = keras.models.Sequential([\n",
        "  keras.layers.SimpleRNN(100, return_sequences=True,\n",
        "                         input_shape=[None, 1]),\n",
        "  keras.layers.SimpleRNN(100, return_sequences=True),\n",
        "  keras.layers.Dense(1),\n",
        "  keras.layers.Lambda(lambda x: x * 200)\n",
        "])\n",
        "lr_schedule = keras.callbacks.LearningRateScheduler(\n",
        "    lambda epoch: 1e-7 * 10**(epoch / 30))\n",
        "optimizer = keras.optimizers.SGD(lr=1e-7, momentum=0.9)\n",
        "model.compile(loss=keras.losses.Huber(),\n",
        "              optimizer=optimizer,\n",
        "              metrics=[\"mae\"])\n",
        "history = model.fit(train_set, epochs=100, callbacks=[lr_schedule])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "YGNsWceq8OI8"
      },
      "outputs": [],
      "source": [
        "plt.semilogx(history.history[\"lr\"], history.history[\"loss\"])\n",
        "plt.axis([1e-7, 1e-4, 0, 30])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "G9lDnb0X8OI9"
      },
      "outputs": [],
      "source": [
        "keras.backend.clear_session()\n",
        "tf.random.set_seed(42)\n",
        "np.random.seed(42)\n",
        "\n",
        "window_size = 30\n",
        "train_set = seq2seq_window_dataset(x_train, window_size,\n",
        "                                   batch_size=128)\n",
        "valid_set = seq2seq_window_dataset(x_valid, window_size,\n",
        "                                   batch_size=128)\n",
        "\n",
        "model = keras.models.Sequential([\n",
        "  keras.layers.SimpleRNN(100, return_sequences=True,\n",
        "                         input_shape=[None, 1]),\n",
        "  keras.layers.SimpleRNN(100, return_sequences=True),\n",
        "  keras.layers.Dense(1),\n",
        "  keras.layers.Lambda(lambda x: x * 200.0)\n",
        "])\n",
        "optimizer = keras.optimizers.SGD(lr=1e-6, momentum=0.9)\n",
        "model.compile(loss=keras.losses.Huber(),\n",
        "              optimizer=optimizer,\n",
        "              metrics=[\"mae\"])\n",
        "early_stopping = keras.callbacks.EarlyStopping(patience=10)\n",
        "model.fit(train_set, epochs=500,\n",
        "          validation_data=valid_set,\n",
        "          callbacks=[early_stopping])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "4mglBRex8OI_"
      },
      "outputs": [],
      "source": [
        "rnn_forecast = model_forecast(model, series[..., np.newaxis], window_size)\n",
        "rnn_forecast = rnn_forecast[split_time - window_size:-1, -1, 0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "Zl_FkcdI8OJA"
      },
      "outputs": [],
      "source": [
        "plt.figure(figsize=(10, 6))\n",
        "plot_series(time_valid, x_valid)\n",
        "plot_series(time_valid, rnn_forecast)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "cznEtSVK8OJB"
      },
      "outputs": [],
      "source": [
        "keras.metrics.mean_absolute_error(x_valid, rnn_forecast).numpy()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "vidayERjaO5q"
      ],
      "name": "l08c06_forecasting_with_rnn.ipynb",
      "private_outputs": true,
      "provenance": [],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
